<!doctype html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Collaborative editing with CodeMirror</title>

  <!-- Firebase -->
  <script src="https://www.gstatic.com/firebasejs/5.5.4/firebase.js"></script>

  <!-- Include CodeMirror -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css" />

  <!-- Firepad -->
  <script src="https://firepad.io/releases/v1.5.9/firepad.min.js"></script>

  <style>
    .CodeMirror pre {
      font-family: Helvetica, sans-serif;
    }
    .cmrt-b { font-weight: bold; }
    .cmrt-i { font-style: italic; }
    .cmrt-u { text-decoration: underline; }
    .cmrt-h1 { font-size: 200%; }
    .cmrt-h2 { font-size: 150%; }
    .cmrt-h3 { font-size: 125%; }
  </style>
</head>

<body onload="init()">
  <h1>Firepad</h1>
  <div id="editor-wrapper">
  <a id="hammer-btn" class="btn" href="#" title="Hammer Time">Hammer Time!</a>
  <span id="hammeringText" style="display: none;">Hammering!</span>

  <script>
    function init() {
      //// Initialize Firebase.
      //// TODO: replace with your Firebase project configuration.
      var config = {
        apiKey: '<API_KEY>',
        authDomain: "firepad-tests.firebaseapp.com",
        databaseURL: "https://firepad-tests.firebaseio.com"
      };
      firebase.initializeApp(config);

      //// Get Firebase Database reference.
      var firepadRef = getExampleRef();

      var editorWrapper = document.getElementById('editor-wrapper');
      var cm = window.cm = CodeMirror(editorWrapper, {
        lineNumbers: true,
        lineWrapping: true,
        mode: 'markdown'
      });
      var firepad = new Firepad(firepadRef, cm);

      var richText = window.location.href.indexOf('#rich') >= 0;

      var nextHammerOp;
      var opNum = 0;
      function doHammerOp() {
        var lastLine = cm.lineCount() - 1;
        var end = cm.indexFromPos({line: lastLine, ch: cm.getLine(lastLine).length});
        var index = Math.floor(Math.random() * (end+1));
        var pos = cm.posFromIndex(index);
        var length = Math.floor(Math.random() * 7);
        var length2 = Math.floor(Math.random() * 7);

        cm.setCursor(cm.posFromIndex(index));

        var op = randInt(0, 100);
        if (op <= 40) { // insert
          var string = randString(length, true);
          if (richText) {
            rtcm.insertText(index, string, randAttributes());
          } else {
            cm.replaceRange(string, pos);
          }
          cm.setCursor(cm.posFromIndex(index + length));
        } else if (op <= 70) {
          if (richText) {
            rtcm.updateTextAttributes(index, Math.min(index + length, end), randAttributes(true));
          } else {
            var from = pos, to = cm.posFromIndex(index + length2);
            var old = cm.getRange(from, to).replace(/\n/g, '\\n');
            var string = randString(length, true);
            cm.replaceRange(string, from, to);
          }
          cm.setCursor(cm.posFromIndex(index + length));
        } else if (op <= 100) { // delete
          var from = pos, to = cm.posFromIndex(index + length);
          cm.replaceRange("", from, to);
        }

        nextHammerOp = setTimeout(doHammerOp, Math.random() * 500);
      }

      function hammer() {
        if (nextHammerOp) {
          clearTimeout(nextHammerOp);
          nextHammerOp = null;
          document.getElementById('hammeringText').style.cssText = "display: none;";
        } else {
          doHammerOp();
          document.getElementById('hammeringText').style.cssText = "display: inline;";
        }
      }

      function preventDefault (e) {
        if (e.preventDefault) { e.preventDefault(); }
      }

      function stopPropagation (e) {
        if (e.stopPropagation) { e.stopPropagation(); }
      }

      function stopEvent (e) {
        preventDefault(e);
        stopPropagation(e);
      }

      var hammerBtn = document.getElementById('hammer-btn');
      hammerBtn.onclick = function(e) { hammer(); stopEvent(e); };

      function randString(length, includeNewlines) {
        var str = ""
        for(var i = 0; i < length; i++) {
          if (includeNewlines && Math.random()*10 < 1)
            str += '\n';
          else
            str += String.fromCharCode(65 + Math.floor(Math.random() * 26));
        }
        return str;
      }

      function randAttributes(isRetain) {
        var attrs = { };
        if (Math.random() > 0.9) {
          attrs['b'] = isRetain ? randBool() : true;
        }
        if (Math.random() > 0.9) {
          attrs['u'] = isRetain ? randBool() : true;
        }
        if (Math.random() > 0.9) {
          attrs['i'] = isRetain ? randBool() : true;
        }
        if (Math.random() > 0.9) {
          attrs['h'] = isRetain ? (randInt(0, 3) || false) : randInt(1, 3);
        }
        return attrs;
      }

      function randBool() {
        return Math.random() > 0.5;
      }

      function randInt(min, max) {
        return min + Math.ceil(Math.random() * (max - min));
      }
    }

    // Helper to get hash from end of URL or generate a random one.
    function getExampleRef() {
      var ref = firebase.database().ref();
      var hash = window.location.hash.replace(/#/g, '');
      if (hash) {
        ref = ref.child(hash);
      } else {
        ref = ref.push(); // generate unique location.
        window.location = window.location + '#' + ref.key; // add it as a hash to the URL.
      }
      if (typeof console !== 'undefined') {
        console.log('Firebase data: ', ref.toString());
      }
      return ref;
    }
</script>
</body>

</html>
